package com.sy.simpleegg.serialport.sycontroller

import android.util.Log
import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.serialport.bean.ComData
import com.sy.simpleegg.serialport.util.ConvertHex
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.cnbleu.serialport.SerialPort

class SyBusinessController(
    portName: String,
    baudrate: SerialPort.BAUDRATE,
    stopb: SerialPort.STOPB,
    datab: SerialPort.DATAB,
    parity: SerialPort.PARITY,
    runHeartBeat: Boolean,
    speed: Long = 10L
) : SyBaseController(portName, baudrate, stopb, datab, parity, speed) {

    private val TAG = javaClass.simpleName

    /**
     * 心跳间隔，正常-10秒 异常-3秒
     */
    private val HEARTBEAT_INTERVAL_CONNECT: Long = 10 * 1000
    /**
     * 心跳间隔，正常-10秒 异常-3秒
     */
    private val HEARTBEAT_INTERVAL_DISCONNECT: Long = 3 * 1000

    /**
     * 出币响应超时次数（12秒，500毫秒检测一次）
     */
    private val OUT_RESP_TIMEOUT: Int = 24
    /**
     * 关闭存币超时
     */
    private val SAVE_RESP_TIMEOUT: Int = 2

    /**
     * 马达1状态 0-正常 1-故障
     */
    private var motor1State = 0
    /**
     * 马达2状态 0-正常 1-故障
     */
    private var motor2State = 0
    /**
     * 出币模式 0-单马达 1-双马达
     */
    private var outType: Int = 0
    /**
     * 出币模式
     */
    private var isOutCoin: Boolean = true
    /**
     * 马达1出币结束
     */
    private var m1OutFinish: Boolean = true
    /**
     * 马达2出币结束
     */
    private var m2OutFinish: Boolean = true
    /**
     * 马达1出币异常
     */
    private var m1Err: Boolean = false
    /**
     * 马达2出币异常
     */
    private var m2Err: Boolean = false
    /**
     * 马达1当前出币数量
     */
    private var m1CurrentOutCount: Long = 0
    /**
     * 马达2当前出币数量
     */
    private var m2CurrentOutCount: Long = 0
    /**
     * 马达1剩余未出币数量
     */
    private var m1RemainCount: Long = 0
    /**
     * 马达2剩余未出币数量
     */
    private var m2RemainCount: Long = 0
    /**
     * 马达1需要出币数量，当马达2故障，需要马达1出币时用到
     */
    private var m1NeedOut: Long = 0
    /**
     * 马达2需要出币数量，当马达1故障，需要马达2出币时用到
     */
    private var m2NeedOut: Long = 0
    /**
     * 马达1出币指令超时，重发指令时用到
     */
    private var m1ReOut: Long = 0
    /**
     * 马达2出币指令超时，重发指令时用到
     */
    private var m2ReOut: Long = 0
    /**
     * 是否收到马达1出币指令响应，判断出币指令超时
     */
    private var receiveOut1: Boolean = true
    /**
     * 是否收到马达2出币指令响应，判断出币指令超时
     */
    private var receiveOut2: Boolean = true
    /**
     *
     */
    private var receiveOut0: Boolean = true
    /**
     * 马达2超时响应次数
     */
    private var m2OutResp: Int = 0
    /**
     * 马达1超时响应次数
     */
    private var m1OutResp: Int = 0
    /**
     * 关闭存币超时次数
     */
    private var saveResp: Int = 0
    /**
     *
     */
    private var checking: Boolean = false
    /**
     * 是否出币中
     */
    private var outing: Boolean = false
    /**
     * 已经出币数量
     */
    private var alreadyOutCount: Long = 0
    /**
     * 当前出币总数量
     */
    private var currentOutCount: Long = 0
    /**
     * 当前剩余未出币总数量
     */
    private var remainCount: Long = 0
    /**
     * 存币数量
     */
    private var saveCount: Long = 0
    /**
     * 是否出币结束
     */
    private var isOutFinish: Boolean = true

    /**
     * 协程
     */
    private var coroutineScope: CoroutineScope? = null
    /**
     * 存币结束超时设置线程
     */
    private var saveRestJob: Job? = null
    /**
     * 马达1超时设置线程
     */
    private var m1OutRespJob: Job? = null
    /**
     * 马达2超时设置线程
     */
    private var m2OutRespJob: Job? = null
    /**
     * 控制板心跳线程
     */
    private var heartBeatJob: Job? = null

    /**
     * 心跳响应状态，发心跳指令前先设置为false，收到心跳响应设置为true
     */
    private var state: Boolean = true
    private var stateCode = 0
    private var errCode = 0

    private var isClearCoin = false
    private var doubleTest = false

    /**
     * 交替出币记数，偶数马达2出币，奇数马达1出币
     */
    private var sort = 0L

    /**
     * 马达清币结束次数，累加到2说明两个马达都清币结束
     */
    private var clear = 0L

    /**
     * 清币数量
     */
    private var clearCoinCount = 0L

    /**
     * 链接状态
     */
    private var isConnect = false

    init {
        log("打开自研控制板，串口号=$portName 波特率=$baudrate 停止位=$stopb 数据位=$datab 校验位=$parity 控制板心跳：${if (runHeartBeat) "开启" else "关闭"}")
        coroutineScope = MainScope()
        if (runHeartBeat) heartBeatLoop()
    }

    fun getConnectState(): Boolean{
        return isConnect
    }

    /**
     * 释放资源
     */
    fun release(){
        close()
        coroutineScope?.cancel()
    }

    /**
     * 设置马达状态
     */
    fun setMotorState(m1State: Boolean, m2State: Boolean){
        motor1State = if (m1State) 0 else 1
        motor2State = if (m2State) 0 else 1
    }

    private fun heartBeatLoop(){
        try {
            heartBeatJob?.cancel()

            heartBeatJob = coroutineScope?.launch (Dispatchers.IO){
                try {
                    run breaking@{
                        while (true){
                            //出币中，不发送心跳指令，直接返回心跳正常
                            if (!isOutFinish) {
                                isConnect = true
                                serialControllerListener?.heartBeat(true, stateCode, errCode)
                                delay(5000)
                                return@breaking
                            }

                            state = true
                            checkState()
                            delay(500)
                            isConnect = !state
                            serialControllerListener?.heartBeat(!state, stateCode, errCode)

                            if (state){
                                delay(HEARTBEAT_INTERVAL_DISCONNECT)
                            }else{
                                delay(HEARTBEAT_INTERVAL_CONNECT)
                            }
                        }
                    }
                }catch (e: Exception){
                    e.printStackTrace()
                    log("心跳处理异常2：" + e.message)
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            log("心跳处理异常：" + e.message)
        }
    }

    /**
     * 存币超时设置
     */
    private fun saveResp(set0rCancel: Boolean){
        try {

            saveRestJob?.cancel()
            saveResp = 0

            if (!set0rCancel) return

            saveRestJob = coroutineScope?.launch (Dispatchers.IO){
                try {
                    while (saveResp >= SAVE_RESP_TIMEOUT){
                        delay(1000)
                        saveResp++
                        val count = saveCount
                        saveCount = 0
                        serialControllerListener?.saveCoinFinish(count)
                    }
                    saveResp = 0
                } catch (e: Exception) {
                    e.printStackTrace()
                    log("存币超时线程处理异常：" + e.message)
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            log("存币超时处理异常：" + e.message)
        }
    }



    /**
     * 马达1超时设置
     * @set0rCancel 设置或者取消
     */
    private fun m1OutResp(set0rCancel: Boolean){
        try {

            m1OutRespJob?.cancel()
            m1OutResp = 0

            //取消马达1超时处理
            if (!set0rCancel) return

            m1OutRespJob = coroutineScope?.launch (Dispatchers.IO){
                try {
                    while (m1OutResp < OUT_RESP_TIMEOUT) {
                        delay(500)
                        m1OutResp++;
                        when (m1OutResp) {
                            1 -> {
                                if (!receiveOut1) {
                                    Log.d(TAG, "重发马达1出币指令")
                                    reSendOutM1()
                                }
                            }
                            2 -> {
                                if (!receiveOut1) receiveOut1 = true;
                            }
                        }
                    }

                    m1OutResp = 0
                    outErrMotor1()
                }catch (e: Exception){
                    e.printStackTrace()
                    log("马达1超时线程处理异常：" + e.message)
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            log("马达1超时处理异常：" + e.message)
        }
    }

    /**
     * 马达2超时设置
     * @set0rCancel 设置或者取消
     */
    private fun m2OutResp(set0rCancel: Boolean){
        try {

            m2OutRespJob?.cancel()
            m2OutResp = 0

            //取消马达2超时处理
            if (!set0rCancel) return

            m2OutRespJob = coroutineScope?.launch (Dispatchers.IO){
                try {
                    while (m2OutResp < OUT_RESP_TIMEOUT) {
                        delay(500)
                        m2OutResp++;
                        when (m2OutResp) {
                            1 -> {
                                if (!receiveOut2) {
                                    Log.d(TAG, "重发马达2出币指令")
                                    reSendOutM2()
                                }
                            }
                            2 -> {
                                if (!receiveOut2) receiveOut2 = true;
                            }
                        }
                    }

                    m2OutResp = 0
                    outErrMotor2()
                }catch (e: Exception){
                    e.printStackTrace()
                    log("马达2超时线程处理异常：" + e.message)
                }
            }

        }catch (e: Exception){
            e.printStackTrace()
            log("马达2超时处理异常：" + e.message)
        }
    }

    /**
     * 重发马达1出币指令
     */
    private fun reSendOutM1(){
        if (m1ReOut > 0) {
            outCoin(1, m1ReOut)
        }
    }

    /**
     * 重发马达2出币指令
     */
    private fun reSendOutM2(){
        if (m2ReOut > 0) {
            outCoin(2, m2ReOut)
        }
    }

    /**
     * 马达1出币故障
     */
    private fun outErrMotor1(){
        try {
            m1OutResp = 0
            m1OutResp(false)
            m1OutFinish = true
            m1Err = true
            serialControllerListener?.motorTimeout(1)
            log("马达1出币超时故障，剩余" + (m1RemainCount + m2RemainCount) + "个币未出")

            if (isClearCoin) {
                Log.d(TAG, "清币马达1清币完成，当前总清币数量：$clearCoinCount")

                clear++

                //交替出币用
                if (motor2State == 0 && clear < 2) {
                    val out = m2CurrentOutCount
                    val reCount = m1RemainCount
                    m1RemainCount = 0
                    alreadyOutCount = out
                    m2NeedOut = m2NeedOut + reCount
                    val afterCount = reCount
                    afterOut(2, afterCount)
                } else {
                    isClearCoin = false
                    serialControllerListener?.onClearCoin(true, clearCoinCount)
                }

                return
            }

            if (doubleTest) {
                Log.d(TAG, "测试双马达出币，马达1故障，当前总出币数量：$currentOutCount")
                if (m1OutFinish && m2OutFinish) {
                    doubleTest = false
                    isOutFinish = true
                    outing = false
                    serialControllerListener?.outCoinFinish(remainCount, currentOutCount, false)
                    clearData()
                }
                return
            }

            motor1State = 1
            serialControllerListener?.onMotorErr(1)

            if (outType == 0) {
                Log.d(TAG, "单马达模式1，结束出币")
                serialControllerListener?.outCoinFinish(
                    (m1RemainCount + m2RemainCount),
                    currentOutCount,
                    false
                )
                return
            }
            if (m2Err || motor2State != 0) {
                Log.d(TAG, "马达1，马达2故障，剩余" + (m1RemainCount + m2RemainCount) + "个币未出");
                serialControllerListener?.outCoinFinish(
                    (m1RemainCount + m2RemainCount),
                    currentOutCount,
                    false
                )
            } else {
                if (m1RemainCount > 0 && m2OutFinish && m2RemainCount == 0L) {
                    val out = m2CurrentOutCount
                    val reCount = m1RemainCount
                    m1RemainCount = 0
                    alreadyOutCount = out
                    //判断马达2出币成功，由马达2继续出币
                    m2NeedOut = m2NeedOut + reCount
                    val afterCount = reCount
                    afterOut(2, afterCount)
                } else if (m1RemainCount == 0L && m2RemainCount == 0L && m2OutFinish) {
                    //出币完成，但是没有收到出币完成指令，
                    Log.d(TAG, "出币完成，但是没有收到马达1出币完成指令")
                    remainCount = 0
                    isOutFinish = true
                    outing = false

                    if (isClearCoin) serialControllerListener?.onClearCoin(true, clearCoinCount)
                    else serialControllerListener?.outCoinFinish(remainCount, currentOutCount, true)

                    clearData()
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            log("马达1故障处理异常：" + e.message)
        }
    }

    /**
     * 马达1出币故障
     */
    private fun outErrMotor2(){
        try {
            m2OutResp = 0
            m2OutResp(false)
            m2OutFinish = true
            m2Err = true
            serialControllerListener?.motorTimeout(2)
            log("马达2出币超时故障，剩余" + (m1RemainCount + m2RemainCount) + "个币未出")

            if (isClearCoin) {
                Log.d(TAG, "清币马达2清币完成，当前总清币数量：$clearCoinCount")

                clear++

                //交替出币用
                if (motor1State == 0 && clear < 2) {
                    val out = m1CurrentOutCount
                    val reCount = m2RemainCount
                    m2RemainCount = 0
                    alreadyOutCount = out
                    m1NeedOut = m1NeedOut + reCount
                    val afterCount = reCount
                    afterOut(1, afterCount)
                } else {
                    isClearCoin = false
                    serialControllerListener?.onClearCoin(true, clearCoinCount)
                }

                return
            }

            if (doubleTest) {
                Log.d(TAG, "测试双马达出币，马达2故障，当前总出币数量：$currentOutCount")
                if (m1OutFinish && m2OutFinish) {
                    doubleTest = false
                    isOutFinish = true
                    outing = false
                    serialControllerListener?.outCoinFinish(remainCount, currentOutCount, false)
                    clearData()
                }
                return
            }

            motor2State = 1
            serialControllerListener?.onMotorErr(2)

            if (outType == 0) {
                Log.d(TAG, "单马达模式2，结束出币")
                serialControllerListener?.outCoinFinish(
                    (m1RemainCount + m2RemainCount),
                    currentOutCount,
                    false
                )
                return
            }
            if (m1Err || motor1State != 0) {
                Log.d(TAG, "马达1，马达2故障，剩余" + (m1RemainCount + m2RemainCount) + "个币未出");
                serialControllerListener?.outCoinFinish(
                    (m1RemainCount + m2RemainCount),
                    currentOutCount,
                    false
                )
            } else {
                if (m2RemainCount > 0 && m1OutFinish && m1RemainCount == 0L) {
                    val out = m1CurrentOutCount
                    val reCount = m2RemainCount
                    m2RemainCount = 0
                    alreadyOutCount = out
                    //判断马达1出币成功，由马达1继续出币
                    m1NeedOut = m1NeedOut + reCount
                    val afterCount = reCount
                    afterOut(1, afterCount)
                } else if (m1RemainCount == 0L && m2RemainCount == 0L && m1OutFinish) {
                    //出币完成，但是没有收到出币完成指令，
                    Log.d(TAG, "出币完成，但是没有收到马达2出币完成指令")
                    remainCount = 0
                    isOutFinish = true
                    outing = false

                    if (isClearCoin) serialControllerListener?.onClearCoin(true, clearCoinCount)
                    else serialControllerListener?.outCoinFinish(remainCount, currentOutCount, true)

                    clearData()
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            log("马达2故障处理异常：" + e.message)
        }
    }

    /**
     * 重置数据
     */
    private fun clearData(){
        m1RemainCount = 0
        m2RemainCount = 0
        m1CurrentOutCount = 0
        m2CurrentOutCount = 0
        m1NeedOut = 0
        m2NeedOut = 0
    }

    /**
     * 马达1出币（带逻辑），单马达模式
     */
    fun outCoinM1Business(count: Long){
        if (!checkOutCount(count)) return
        if (motor1State != 0 && motor2State != 0){
            Log.d(TAG, "双马达故障，无法出币")
            return
        }else if (motor1State != 0 && motor2State == 0){
            Log.d(TAG, "马达1故障，马达2正常，改由马达2出币")
            outCoinM2Business(count)
            return
        }

        //单马达模式
        outType = 0
        isOutFinish = false
        remainCount = count
        currentOutCount = 0
        alreadyOutCount = 0
        outing = false
        checking = true
        m2RemainCount = 0
        m2CurrentOutCount = 0
        m1OutResp = 0
        m2OutResp = 0

        m1NeedOut = count
        m1RemainCount = count
        m1CurrentOutCount = 0

        m2Err = true
        m2OutFinish = true
        m1OutFinish = false

        isOutCoin = true
//        outResp = 0

        //发送出币指令开始倒计时，如果5秒没有收到出币响应（F6指令），则出币失败
        m1OutResp(true)
        m1ReOut = count
        receiveOut1 = false
        outCoin(1, count)
    }

    /**
     * 马达2出币（带逻辑），单马达模式
     */
    fun outCoinM2Business(count: Long){
        if (!checkOutCount(count)) return
        if (motor2State != 0 && motor1State != 0){
            Log.d(TAG, "双马达故障，无法出币")
            return
        }else if (motor2State != 0 && motor1State == 0){
            Log.d(TAG, "马达2故障，马达1正常，改由马达1出币")
            outCoinM1Business(count)
            return
        }

        //单马达模式
        outType = 0
        isOutFinish = false
        remainCount = count
        currentOutCount = 0
        alreadyOutCount = 0
        outing = false
        checking = true
        m1RemainCount = 0
        m1CurrentOutCount = 0
        m1OutResp = 0
        m2OutResp = 0

        m2NeedOut = count
        m2RemainCount = count
        m2CurrentOutCount = 0

        m1Err = true
        m1OutFinish = true
        m2OutFinish = false

        isOutCoin = true
//        outResp = 0

        //发送出币指令开始倒计时
        m2OutResp(true)
        m2ReOut = count
        receiveOut2 = false
        outCoin(2, count)
    }

    /**
     * 双马达出币（带逻辑）
     */
    fun doubleOutCoinBusiness(count: Long){
        if (!checkOutCount(count)) return
        //双马达模式
        outType = 1

        if (!isClearCoin && !doubleTest){
            if (motor1State == 0 && motor2State != 0){
                log("双马达模式，马达2故障，改为马达1的单马达出币")
                outCoinM1Business(count)
                return
            }else if (motor1State != 0 && motor2State == 0){
                log("双马达模式，马达1故障，改为马达2的单马达出币")
                outCoinM2Business(count)
                return
            }else if (motor1State != 0 && motor2State != 0){
                log("双马达模式，马达故障，无法出币")
                return
            }
        }

        remainCount = count
        currentOutCount = 0
        alreadyOutCount = 0
        m1CurrentOutCount = 0
        m2CurrentOutCount = 0

        isOutFinish = false
        outing = false
        checking = true
        isOutCoin = true

        m1OutFinish = false
        m2OutFinish = false
        m1Err = false
        m2Err = false

        m1OutResp = 0
        m2OutResp = 0

        when(count){
            1L -> {
                m1RemainCount = 1
                m2RemainCount = 0
            }
            else -> {
                if (count % 2L == 0L){
                    //偶数
                    m1RemainCount = count / 2
                    m2RemainCount = count / 2
                }else{
                    //奇数
                    m1RemainCount = (count - 1) / 2 + 1;
                    m2RemainCount = (count - 1) / 2;
                }
            }
        }

        Log.d(TAG, "双马达出币：马达1需要出币" + m1RemainCount + " 马达2需要出币" + m2RemainCount)

        m1NeedOut = m1RemainCount
        m2NeedOut = m2RemainCount

        outCoinM1TypeDouble(m1RemainCount)

        coroutineScope?.launch (Dispatchers.IO){
            delay(1500)
            outCoinM2TypeDouble(m2RemainCount)
        }
    }

    /**
     * 双马达模式中，马达1出币
     */
    private fun outCoinM1TypeDouble(count: Long){
        receiveOut1 = false
        m1ReOut = count
        m1OutResp(true)
        outCoin(1, count)
    }

    /**
     * 双马达模式中，马达2出币
     */
    private fun outCoinM2TypeDouble(count: Long){
        receiveOut2 = false
        m2ReOut = count
        m2OutResp(true)
        outCoin(2, count)
    }

    /**
     * 双马达模式出币，其中一个马达故障后，启动另外一个马达出币
     */
    private fun afterOut(type: Int, count: Long){

        when(type){
            1 -> {
                Log.d(TAG, "双马达模式，马达2出币故障，剩余" + count + "个币未出，由马达1继续出币")
                m1ReOut = count
                receiveOut1 = false
                m1OutResp(true)
                outCoin(1, count)
            }
            2 -> {
                Log.d(TAG, "双马达模式，马达1出币故障，剩余" + count + "个币未出，由马达2继续出币")
                m2ReOut = count
                receiveOut2 = false
                m2OutResp(true)
                outCoin(2, count)
            }
            else -> {
                Log.d(TAG, "未知出币类型")
                return
            }
        }
    }

    /**
     * 双马达交替出币（带逻辑）
     */
    fun outCoinAlternately(count: Long){
        if (!checkOutCount(count)) return
        outType = 1
        if (!isClearCoin && !doubleTest){
            if (motor1State == 0 && motor2State != 0){
                Log.d(TAG, "交替双马达模式，马达2故障，改为马达1的单马达出币")
                outCoinM1Business(count)
                return
            }else if (motor1State != 0 && motor2State == 0){
                Log.d(TAG, "交替双马达模式，马达1故障，改为马达2的单马达出币")
                outCoinM2Business(count)
                return
            }else if (motor1State != 0 && motor2State != 0){
                Log.d(TAG, "交替双马达模式，马达故障，无法出币")
                return
            }
        }

        Log.d(TAG, "交替双马达模式，马达都正常，允许出币")

        isOutFinish = false
        remainCount = count
        currentOutCount = 0
        alreadyOutCount = 0

        m1RemainCount = 0
        m2RemainCount = 0
        m1CurrentOutCount = 0
        m2CurrentOutCount = 0

        outing = false
        checking = true

        isOutCoin = true

        if (sort % 2 == 0L){
            m2RemainCount = count
        }else if (sort % 2 == 1L){
            m1RemainCount = count
        }

        m1NeedOut = m1RemainCount
        m2NeedOut = m2RemainCount

        m1OutFinish = false
        m1Err = false
        m2OutFinish = false
        m2Err = false

        if (sort % 2 == 0L){
            m1OutFinish = true
            outCoinM2Business(count)
        }else if (sort % 2 == 1L){
            m2OutFinish = true
            outCoinM1Business(count)
        }
        sort ++
    }

    /**
     * 双马达清币
     */
    fun clearCoinDouble(){
        isClearCoin = true
        doubleOutCoinBusiness(65535)
    }

    /**
     * 双马达交替清币
     */
    fun clearCoinAlternately(){
        isClearCoin = true
        clear = 0
        outCoinAlternately(65535)
    }

    /**
     * 存币
     */
    fun saveCoin(open: Boolean){
        if (open) {
            startInCoin()
        } else {
            saveResp(true)
            stopInCoin()
        }
    }

    /**
     * 双马达出币，无逻辑，测试用
     */
    fun doubleOutCoinTest(count: Long){
        doubleTest = true
        doubleOutCoinBusiness(count)
    }

    /**
     * 马达交替清币 测试
     */
    fun clearCoinAlternatelyTest(){
        doubleTest = true
        clearCoinAlternately()
    }

    /**
     * 马达1出币（无逻辑，测试用）
     */
    fun outCoinM1SingleTest(count: Long){
        if (!checkOutCount(count)) return
        isOutFinish = false
        remainCount = count
        currentOutCount = 0
        alreadyOutCount = 0
        outing = false
        checking = true

        outType = 0

        m1NeedOut = count
        m1RemainCount = count
        m1CurrentOutCount = 0
        m2NeedOut = 0
        m2RemainCount = 0
        m2CurrentOutCount = 0

        m2Err = true
        m2OutFinish = true
        m1OutFinish = false

        isClearCoin = false
        isOutCoin = true

        m1OutResp = 0
        m1OutResp(true)
        outCoin(1, count)
    }

    /**
     * 马达2出币（无逻辑，测试用）
     */
    fun outCoinM2SingleTest(count: Long){
        if (!checkOutCount(count)) return
        isOutFinish = false
        remainCount = count
        currentOutCount = 0
        alreadyOutCount = 0
        outing = false
        checking = true

        outType = 0

        m2NeedOut = count
        m2RemainCount = count
        m2CurrentOutCount = 0
        m1NeedOut = 0
        m1RemainCount = 0
        m1CurrentOutCount = 0

        m1Err = true
        m1OutFinish = true
        m2OutFinish = false

        isClearCoin = false
        isOutCoin = true

        m2OutResp = 0
        m2OutResp(true)
        outCoin(2, count)
    }

    fun rebootBoard(){
        reboot()
    }



    /**
     * 校验出币数量
     */
    private fun checkOutCount(count: Long):Boolean{
        if (count <= 0) serialControllerListener?.countErr(count)
        return count > 0
    }

    override fun onDataReceived(comData: ComData) {

        val dataHex = ConvertHex.byte2hex(comData.data)
        log("收到控制板数据：$dataHex")

        when (dataHex.substring(0, 4)){
            "0110" -> normalRespHandle(dataHex)
            "0103" -> readStateRespHandle(dataHex)
            "01F6" -> coinRespHandle(dataHex)
            else -> log("收到未知指令数据：$dataHex")
        }
    }

    override fun cmdTimeout(comData: ComData) {
        logFile("指令响应超时：${comData.data} ")
    }

    /**
     * 马达出币指令响应处理
     */
    private fun normalRespHandle(dataHex: String){
        try {
            if (dataHex.equals("011000330005F005") && isOutCoin) {
                if (!receiveOut1) {
                    log("收到马达1出币响应")
                    receiveOut1 = true
                    return
                }

                if (!receiveOut2) {
                    log("收到马达2出币响应")
                    receiveOut2 = true
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            log("处理马达出币指令响应异常：" + e.message)
        }
    }

    /**
     * 读控制板状态数据处理
     */
    private fun readStateRespHandle(dataHex: String){
        try {
            val len = dataHex.substring(4, 6).toInt(16)
            when (len){
                4 -> {
                    //心跳数据
                    log("控制板心跳数据：" + dataHex)
                    if (state){
                        state = false
                        val errHex = dataHex.substring(6, 10)
                        val stateHex = dataHex.substring(10, 14)
                        errCode = errHex.toInt(16)
                        stateCode = stateHex.toInt(16)
                        serialControllerListener?.heartBeat(true, stateCode, errCode)
                    }
                }
                6 -> {
                    //出币查询数据
                }
                else -> log("控制板状态响应数据：" + dataHex)
            }
        }catch (e: Exception){
            e.printStackTrace()
            log("读控制板状态数据处理异常：" + e.message)
        }

    }

    /**
     * 出币（存币）响应数据处理
     */
    private fun coinRespHandle(dataHex: String){
        log("出（存）币数据：$dataHex")
        //事件类型 "0025"-存币 "0026"-出币 "0027"-出币完成
        val eventType = dataHex.substring(4, 8)
        //控制器 "0001"-马达1（或者投币器1） "0101"-马达2（或者投币器2）
        val controller = dataHex.substring(14, 18)
        //剩余币数
        val remainCoin = dataHex.substring(18, 22)
        val remain = remainCoin.toInt(16)
        Log.d("SerialCoin", "出币响应：remainCoin=$remainCoin remain=$remain")

        when{
            isOutCoin && "0026" == eventType -> {
                //出币信息处理
                handleCoinInfo(controller, remain)
            }
            !isOutCoin && "0025" == eventType -> {
                //存币
                saveResp = 0
                saveCount ++
            }
            "0027" == eventType -> {
                //出币完成处理
                handleCoinFinish(dataHex)
            }
            "0028" == eventType -> {
                //马达状态
                val m1s = dataHex.substring(14, 16)
                val m2s = dataHex.substring(16, 18)

//                parseMotorState(m1s);

                Log.d(TAG, "马达状态：马达1-$m1s 马达2-$m2s")
            }
            "0029" == eventType -> {
                //01F60029 0002 04 01 00 0027 9472

                //01F60029 0002 04 01 00 0027 9472
                val motor = dataHex.substring(14, 16).toInt()
                val reCount = dataHex.substring(18, 22).toInt(16)
                Log.d(TAG, "出币异常 马达$motor 剩余未出币数 $reCount")

                if (motor == 1) {
                    m1RemainCount = reCount.toLong()
                    outErrMotor1()
                } else if (motor == 2) {
                    m2RemainCount = reCount.toLong()
                    outErrMotor2()
                } else {
                    Log.d(TAG, "出币异常：未知异常中断")
                }
            }
            else -> Log.d(TAG,"状态异常,当前为" + (if (isOutCoin) "出币模式" else "存币模式") + " 收到指令为：" + dataHex)
        }

        Log.d(TAG, "刷新页面数据，币数：" + if (isOutCoin) remainCount else saveCount)
        serialControllerListener?.onCoinRefresh(if (isOutCoin) remainCount else saveCount, isOutCoin)
    }

    /**
     * 出币信息处理
     */
    private fun handleCoinInfo(controller: String, remain: Int){
        when (controller){
            "0001" -> {
                receiveOut1 = true
                m1OutResp = 0
                m1RemainCount = remain.toLong()
                m1CurrentOutCount = m1NeedOut - remain
                Log.d(TAG, "马达1出币 $m1CurrentOutCount")
            }
            "0002" -> {
                receiveOut2 = true
                m2OutResp = 0
                m2RemainCount = remain.toLong()
                m2CurrentOutCount = m2NeedOut - remain
                Log.d(TAG, "马达2出币 $m2CurrentOutCount")
            }
            else -> Log.d(TAG, "未知控制器 controller：$controller")
        }

        currentOutCount = m1CurrentOutCount + m2CurrentOutCount
        remainCount = m1RemainCount + m2RemainCount
        Log.d(
            TAG,
            "当前总出币数" + currentOutCount + "个" + " 剩余未出币总数" + remainCount + "个，其中"
        )

        if (isClearCoin){
            clearCoinCount = currentOutCount
            Log.d(TAG, "清币数量：$clearCoinCount")
            serialControllerListener?.onClearCoin(false, clearCoinCount)
            return
        }
    }

    /**
     * 出币完成处理
     */
    private fun handleCoinFinish(dataHex: String){

        //01F600270001020101EEB5
        //01F600270001020101EEB5
        val finishType = dataHex.substring(14, 18)

        when (finishType){
            "0101" -> {
                //马达1出币完成
                m1OutResp = 0
                m1OutFinish = true
                m1RemainCount = 0
                m1CurrentOutCount = m1NeedOut - m1RemainCount
                m1OutResp(false)
                Log.d(
                    TAG,
                    "马达1出币完成" + m1CurrentOutCount + "个" + " 剩余未出币数" + m1RemainCount + "个"
                )
                if (outType != 0 && !doubleTest) {
                    //马达2故障，马达1继续出币，
                    if (m2OutFinish && m2RemainCount > 0 && m2Err) {
                        val out = m2CurrentOutCount
                        alreadyOutCount = out
                        //判断马达1出币成功，由马达1继续出币
                        m1NeedOut = m1NeedOut + m2RemainCount
                        val afterCount = m2RemainCount
                        afterOut(1, afterCount)
                    }
                }
            }
            "0201" -> {
                //马达2出币完成
                m2OutResp = 0
                m2OutFinish = true
                m2RemainCount = 0
                m2CurrentOutCount = m2NeedOut - m2RemainCount
                m2OutResp(false)
                Log.d(
                    TAG,
                    "马达2出币完成" + m2CurrentOutCount + "个" + " 剩余未出币数" + m2RemainCount + "个"
                )
                if (outType != 0 && !doubleTest) {
                    //马达1故障，马达2继续出币，
                    if (m1OutFinish && m1RemainCount > 0 && m1Err) {
                        val out = m2CurrentOutCount
                        alreadyOutCount = out
                        //判断马达2出币成功，由马达2继续出币
                        m2NeedOut = m2NeedOut + m1RemainCount
                        val afterCount = m1RemainCount
                        afterOut(2, afterCount)
                    }
                }
            }
            else -> Log.d(TAG, "未知出币完成类型 $dataHex")
        }

        currentOutCount = m1CurrentOutCount + m2CurrentOutCount
        remainCount = m1RemainCount + m2RemainCount
        Log.d(
            TAG,
            "当前总出币数" + currentOutCount + "个" + " 剩余未出币总数" + remainCount + "个"
        )
        Log.d(
            TAG,
            "m1OutFinish=$m1OutFinish m2OutFinish=$m2OutFinish"
        )

        //判断是否出币结束
        if (m1OutFinish && m2OutFinish && isOutCoin) {
            if (doubleTest) {
                doubleTest = false
            }
            remainCount = 0
            isOutFinish = true
            outing = false
            if (isClearCoin) {
                serialControllerListener?.onClearCoin(true, clearCoinCount)
            } else {
                serialControllerListener?.outCoinFinish(remainCount, currentOutCount, true)
            }
            clearData()
        }
    }

    private var serialControllerListener: SerialControllerListener? = null
    interface SerialControllerListener{
        /**
         * 心跳数据回调
         */
        fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int)

        /**
         * 出币数异常回调
         */
        fun countErr(count: Long)

        /**
         * 马达出币超时回到
         */
        fun motorTimeout(motorNumber: Int)

        /**
         * 清币回调
         */
        fun onClearCoin(clearFinish: Boolean, clearCoinCount: Long)

        /**
         * 出币数据回调
         */
        fun outCoinFinish(remainCount: Long, currentOutCount: Long, outFinish: Boolean)

        /**
         * 马达故障
         */
        fun onMotorErr(motorNumber: Int)

        /**
         * 存币结束
         */
        fun saveCoinFinish(count: Long)

        /**
         * 刷新出币或存币数据
         */
        fun onCoinRefresh(coinCount: Long, outOrSave: Boolean)
    }

    fun setSerialControllerListener(listener: SerialControllerListener){
        this.serialControllerListener = listener
    }

    private fun log (msg: String){
        logFile(msg)
    }

}